﻿#region Copyright ©2008-2010, Technische Universitaet Muenchen
// ====================================================================================================
//
// Last Changed by       $Author: then $
// Last Changed Date     $LastChangedDate: 2009-06-15 08:45:45 +0200 (Mon, 15 Jun 2009) $
// Last Changed Revision $Rev: 194 $
//
// ====================================================================================================
#endregion

using System;
using System.Threading;
using System.Windows.Media;
using System.Windows.Documents;

namespace Tum.CollabXT.Wizard
{
    /// <summary>
    /// Interaction logic for ProcessingPage.xaml
    /// </summary>
    internal partial class ProcessingPage : InternalConversionWorkflowPage
    {
        /// <summary>
        /// Used conversion workflow.
        /// </summary>
        ConversionWorkflow Workflow;

        /// <summary>
        /// Processing thread.
        /// </summary>
        Thread ProcessingThread;

        /// <summary>
        /// Has the processing already completed?
        /// </summary>
        bool ProcessingCompleted = false;


        /// <summary>
        /// Constructor.
        /// </summary>
        public ProcessingPage()
        {
            InitializeComponent();

            tbLog.Document = new System.Windows.Documents.FlowDocument();
        }

        /// <summary>
        /// Receives the conversion workflow.
        /// </summary>
        /// <param name="workflow">Conversion workflow.</param>
        /// <returns>True, if the workflow has been received correctly, false if not.</returns>
        public override bool InternalReceiveWorkflowHandle(ConversionWorkflow workflow)
        {
            Workflow = workflow;

            if (!Workflow.ValidProcessingExists)
            {
                Workflow.UpdateButtonState(true, false);

                //Register log handler ... all new log items will be shown in list
                Workflow.Log.LogEntryAdded += new Log.LogEntryAddedDelegate(Log_LogEntryAdded);

                ProcessingThread = new Thread(new ThreadStart(ProcessThread));
                ProcessingThread.Start();

                return true;
            }
            else
                return false;
        }

        /// <summary>
        /// Event handler for a new log entry.
        /// </summary>
        private void Log_LogEntryAdded(string entry, DateTime timeAdded, LogEntryType entryType)
        {
            //Invoke the list-adding function
            this.Dispatcher.Invoke(new AddLogListEntryDelegate(AddLogListEntry), entry, entryType);
        }


        /// <summary>
        /// Delegate type for AddLogListEntry.
        /// </summary>
        delegate void AddLogListEntryDelegate(string entry, LogEntryType entryType);

        /// <summary>
        /// Adds a new log entry.
        /// </summary>
        /// <param name="entry">Entry message.</param>
        /// <param name="entryType">Type of the new entry.</param>
        private void AddLogListEntry(string entry, LogEntryType entryType)
        {
            Brush foregroundBrush = null;
            switch (entryType)
            {
                case LogEntryType.Warning:
                    foregroundBrush = new SolidColorBrush(Colors.Orange);
                    break;
                case LogEntryType.Error:
                    foregroundBrush = new SolidColorBrush(Colors.Red);
                    break;
                case LogEntryType.Status:
                default:
                    foregroundBrush = new SolidColorBrush(Colors.Black);
                    break;
            }

            //Add entry
            Paragraph para = new Paragraph(new Run(entry));
            para.Foreground = foregroundBrush;
            para.Margin = new System.Windows.Thickness(0);

            lock (tbLog)
            {
                tbLog.Document.Blocks.Add(para);
                tbLog.ScrollToEnd();
            }
        }

        /// <summary>
        /// Delegate tyoe for SetProgress.
        /// </summary>
        delegate void SetProgressDelegate(int progress);

        /// <summary>
        /// Sets the current conversion progress bar state.
        /// </summary>
        /// <param name="progress">Current progress [0, 100].</param>
        private void SetProgress(int progress)
        {
            progressBar.Value = progress;
        }

        /// <summary>
        /// Previous page has been requested.
        /// </summary>
        /// <returns>True, if the page change is allowed, false if not.</returns>
        public override bool PrevPageRequested()
        {
            lock (ProcessingThread)
            {
                if (!ProcessingCompleted)
                {
                    if (ProcessingThread != null)
                    {
                        ProcessingThread.Abort();
                        ProcessingThread.Join(500);

                        AddLogListEntry(Environment.NewLine, LogEntryType.Status);
                        Workflow.Log.AddEntry("Processing interrupted by user.", LogEntryType.Error);
                    }
                }
            }
            return true;
        }

        /// <summary>
        /// Next page has been requested.
        /// </summary>
        /// <returns>True, if the page change is allowed, false if not.</returns>
        public override bool NextPageRequested()
        {
            lock (ProcessingThread)
            {
                return ProcessingCompleted;
            }
        }


        /// <summary>
        /// Processing thread.
        /// </summary>
        void ProcessThread()
        {
            try
            {
                this.Dispatcher.Invoke(new SetProgressDelegate(SetProgress), 10);

                //Reset warnings and errors count
                Workflow.Log.ResetErrorAndWarningCounters();


                int curProgress = 10;

                foreach (var curToolProvider in Workflow.Project.ToolProviders)
                {
                    if (curToolProvider.Initialized)
                        curToolProvider.Instance.Process();
                    else
                        Workflow.Log.AddEntry("Tool provider is not initialized.", LogEntryType.Error);

                    curProgress += 90 / Workflow.Project.ToolProviders.Count;
                    this.Dispatcher.Invoke(new SetProgressDelegate(SetProgress), curProgress);

                    Workflow.Log.AddSeparator();
                    Workflow.Log.AddSeparator();
                }

                lock (ProcessingThread)
                {
                    ProcessingCompleted = true;
                }
                Workflow.ValidateProcessing();
                Workflow.UpdateButtonState(true, true);
                this.Dispatcher.Invoke(new SetProgressDelegate(SetProgress), 100);


                //Write completion message
                string warningStr = string.Empty;
                if (Workflow.Log.WarningCount > 0)
                    warningStr = string.Format(Wizard.Resources.Language.Message_NumberWarnings,
                        Workflow.Log.WarningCount);

                Workflow.Log.AddSeparator();
                Workflow.Log.AddEntry(Wizard.Resources.Language.Meesage_ProcessingComplete + " " + warningStr);
            }
            catch(Exception e)
            {
                string errorText = string.Format(Wizard.Resources.Language.Error_ProcessingFailed, Environment.NewLine, e.Message);
                errorText += Environment.NewLine;
                errorText += Environment.NewLine;
                errorText += e.StackTrace;
                this.Dispatcher.Invoke(new AddLogListEntryDelegate(AddLogListEntry), 
                    errorText, LogEntryType.Error);
            }
        }
    }
}
